﻿using RockBus.DataContracts;
using System;
using System.Collections.Generic;
using System.Configuration;

namespace RockBus.Configuration
{
    public partial class ServiceBusConfigurationSection
    {
        public void Refresh()
        {
            ConfigurationManager.RefreshSection(ServiceBusConfigurationSection.ServiceBusConfigurationSectionSectionName);
        }
    }

    public partial class ServiceBusSubscriberConfigurations
    {
        public SubscriberConfiguration CreateSubscriberConfiguration(bool isStatic)
        {
            SubscriberConfiguration sc = new SubscriberConfiguration();
            foreach (SubscriberInfo si in this.CreateSubscriberInfos(isStatic))
            {
                sc.EvaluationElementDictionary.Add(si.Id, si);
            }
            return sc;
        }

        public IEnumerable<string> GetSubscriberIds()
        {
            foreach (ServiceBusSubscriberConfiguration ssc in this)
            {
                yield return ssc.Id;
            }
        }

        public IEnumerable<PipelineInfo> CreatePipelineInfos()
        {
            foreach (ServiceBusSubscriberConfiguration spc in this)
            {
                foreach (Pipeline p in spc.Pipelines)
                {
                    yield return p.CreatePipelineInfo();
                }
            }
        }

        public IEnumerable<SubscriberInfo> CreateSubscriberInfos(bool isStatic)
        {
            foreach (ServiceBusSubscriberConfiguration ssc in this)
            {
                // Create default subscriber
                SubscriberInfo si = new SubscriberInfo(
                    ssc.Id,
                    isStatic,
                    ssc.CreateNamespaceInfos(),
                    ssc.CreateFilterInfos(),
                    ssc.CreateEndpointInfos(),
                    ssc.CreatePipelineInfos());

                foreach (Subscription sub in ssc.Subscriptions)
                {
                    si.AddSubscriptionInfo(
                        sub.CreateSubscriptionDetail(si.Id),
                        sub.GetFilterIds());
                }

                yield return si;
            }
        }
    }

    public partial class ServiceBusSubscriberConfiguration
    {
        public IEnumerable<NamespaceInfo> CreateNamespaceInfos()
        {
            foreach (NamespaceDefinition nsd in this.Namespaces)
            {
                yield return nsd.CreateNamespaceInfo();
            }
        }

        public IEnumerable<FilterInfo> CreateFilterInfos()
        {
            foreach (Filter f in this.Filters)
            {
                yield return f.CreateFilterInfo();
            }
        }

        public IEnumerable<EndpointInfo> CreateEndpointInfos()
        {
            foreach (Endpoint ep in this.Endpoints)
            {
                yield return ep.CreateEndpointInfo();
            }
        }

        public IEnumerable<PipelineInfo> CreatePipelineInfos()
        {
            foreach (Pipeline p in this.Pipelines)
            {
                yield return p.CreatePipelineInfo();
            }
        }
    }

    public partial class ServiceBusPublisherConfigurations
    {
        public PublisherConfiguration CreatePublisherConfiguration()
        {
            PublisherConfiguration pc = new PublisherConfiguration();
            foreach (PublisherInfo pi in this.CreatePublisherInfos())
            {
                pc.EvaluationElementDictionary.Add(pi.Id, pi);
            }
            return pc;
        }

        public IEnumerable<string> GetPublisherIds()
        {
            foreach (ServiceBusPublisherConfiguration spc in this)
            {
                yield return spc.Id;
            }
        }

        public IEnumerable<PublisherInfo> CreatePublisherInfos()
        {
            foreach (ServiceBusPublisherConfiguration spc in this)
            {
                // Create default subscriber
                PublisherInfo pi = new PublisherInfo(
                    spc.Id,
                    true,
                    spc.CreateEndpointInfos(),
                    spc.CreatePipelineInfos(),
                    spc.CreateResponseInfos(),
                    null
                );

                foreach (ReceivePort adv in spc.ReceivePorts)
                {
                    pi.AddReceivePortInfo(
                        adv.CreateReceivePortDetail(pi.Id),
                        responseId: adv.ResponseId,
                        generateDefaultResponse: adv.GenerateDefaultResponse);
                }

                yield return pi;
            }
        }

        public IEnumerable<ResponseInfo> CreateResponseInfos()
        {
            foreach (ServiceBusPublisherConfiguration spc in this)
            {
                foreach (Response r in spc.Responses)
                {
                    yield return r.CreateResponseInfo();
                }
            }
        }
    }

    public partial class ServiceBusPublisherConfiguration
    {
        public IEnumerable<EndpointInfo> CreateEndpointInfos()
        {
            foreach (Endpoint ep in this.Endpoints)
            {
                yield return ep.CreateEndpointInfo();
            }
        }

        public IEnumerable<ResponseInfo> CreateResponseInfos()
        {
            foreach (Response r in this.Responses)
            {
                yield return r.CreateResponseInfo();
            }
        }

        public IEnumerable<PipelineInfo> CreatePipelineInfos()
        {
            foreach (Pipeline p in this.Pipelines)
            {
                yield return p.CreatePipelineInfo();
            }
        }
    }

    public partial class Endpoint
    {
        public EndpointInfo CreateEndpointInfo()
        {
            return new EndpointInfo()
            {
                Id = this.Id,
                TransportType = (DataContracts.TransportTypeEnum)this.TransportType,
                ExchangeType = (DataContracts.ExchangeTypeEnum)this.ExchangeType,
                EndpointName = (DataContracts.EndpointNameEnum)this.EndpointName,
                CustomEndpointName = this.CustomEndpointName,
                Address = this.Address,
                TransactionScopeOption = (System.Transactions.TransactionScopeOption)this.TransactionScopeOption,
                AddRoutingHeader = this.AddRoutingHeader,
            };
        }
    }

    public partial class Filter
    {
        public FilterInfo CreateFilterInfo()
        {
            return new FilterInfo()
            {
                Id = this.Id,
                FilterType = (DataContracts.FilterTypeEnum)this.FilterType,
                FilterData = this.FilterData,
                Filter1Id = this.Filter1Id,
                Filter2Id = this.Filter2Id,
                CustomTypeName = this.CustomTypeName,
            };
        }
    }

    public partial class NamespaceDefinition
    {
        public NamespaceInfo CreateNamespaceInfo()
        {
            return new NamespaceInfo()
            {
                Prefix = this.Prefix,
                Namespace = this.Namespace,
            };
        }
    }

    public partial class Subscription
    {
        public SubscriptionDetail CreateSubscriptionDetail(string parentId)
        {
            var sd = new SubscriptionDetail(
                parentId,
                this.Id,
                this.Name,
                this.EndpointId,
                this.Persistent,
                this.MessageValidityDuration,
                (this.DeliveryAttemptInterval == TimeSpan.Zero) ? null : (TimeSpan?)this.DeliveryAttemptInterval,
                (this.MaxDeliveryAttemptCount <= 0) ? null : (int?)this.MaxDeliveryAttemptCount,
                expiryDateTimeUtc: (this.ExpiryDateTimeUtc == DateTime.MinValue) ? null : (DateTime?)this.ExpiryDateTimeUtc,
                requestPipelineId: this.RequestPipelineId,
                responsePipelineId: this.ResponsePipelineId);
            return sd;
        }

        private readonly char[] _splitChars = new char[] { ',', ';' };

        public IEnumerable<string> GetFilterIds()
        {
            string[] filterIds = this.FilterIds.Split(this._splitChars);
            if ((null != filterIds) && (filterIds.Length > 0))
                foreach (string filterId in filterIds)
                {
                    if (string.IsNullOrEmpty(filterId))
                    {
                        continue;
                    }

                    string filterId2 = filterId.Trim();
                    if (string.IsNullOrEmpty(filterId2))
                    {
                        continue;
                    }

                    yield return filterId2;
                }

            for (int i = 0; i < this.Filters.Count; i++)
            {
                SubscriptionElementReference ser = this.Filters[i];
                yield return ser.Id;
            }
        }
    }

    public partial class ReceivePort
    {
        public ReceivePortDetail CreateReceivePortDetail(string parentId)
        {
            ReceivePortDetail ad = new ReceivePortDetail(
                parentId,
                this.Id,
                this.Name,
                this.EndpointId,
                false,
                (this.ExpiryDateTimeUtc == DateTime.MinValue) ? null : (DateTime?)this.ExpiryDateTimeUtc,
                this.RequestPipelineId,
                this.ResponsePipelineId);
            return ad;
        }

        public ReceivePortInfo CreateReceivePortInfo(PublisherInfo pi)
        {
            ReceivePortDetail rpd = this.CreateReceivePortDetail(pi.Id);
            ReceivePortInfo ai = new ReceivePortInfo(
                pi,
                rpd,
                responseId: this.ResponseId,
                generateDefaultResponse: this.GenerateDefaultResponse);
            return ai;
        }
    }

    public partial class Response
    {
        public ResponseInfo CreateResponseInfo()
        {
            return new ResponseInfo(
                this.Id,
                this.ResponseAction,
                this.Xml,
                this.BufferSize);
        }
    }

    public partial class Pipeline
    {
        public PipelineInfo CreatePipelineInfo()
        {
            var pi = new PipelineInfo(this.Id, this.CreatePipelineComponents());
            return pi;
        }

        public IEnumerable<PipelineComponentInfo> CreatePipelineComponents()
        {
            foreach (var pcObj in this)
            {
                var pc = pcObj as PipelineComponent;
                yield return pc.CreatePipelineComponentInfo();
            }
        }
    }

    public partial class PipelineComponent
    {
        public PipelineComponentInfo CreatePipelineComponentInfo()
        {
            return new PipelineComponentInfo(this.Id, this.TypeName, this.Active, this.SoapActionFilter, this.PropertyBag.CreateKeyValuePairs());
        }
    }

    public partial class PropertyBag
    {
        public IEnumerable<KeyValuePair<string, string>> CreateKeyValuePairs()
        {
            foreach (var propertyObj in this)
            {
                var kvp = propertyObj as Property;
                yield return new KeyValuePair<string, string>(kvp.Key, kvp.Value);
            }
        }
    }
}